package io.sundial.engine.impl;

import io.sundial.coordination.CallbackException;
import io.sundial.coordination.Coordinator;
import io.sundial.coordination.CoordinatorException;
import io.sundial.coordination.node.NodeEvent;
import io.sundial.coordination.node.NodeWatcher;
import io.sundial.core.Callback;
import io.sundial.core.context.Context;
import io.sundial.core.lifecycle.exception.DestroyingException;
import io.sundial.core.lifecycle.exception.InitializingException;
import io.sundial.engine.exception.ShuttingException;
import io.sundial.engine.exception.StartingException;
import io.sundial.util.NetKit;

/**
 * 命名的引擎
 *
 * @author Payne 646742615@qq.com
 * 2018/12/24 13:15
 */
public abstract class NamedEngine extends ProtocolEngine {
    protected static final String SPRT = "/";
    protected static final String ENGINES_ROOT = SPRT + "engines";

    protected String name = NetKit.address();
    protected Coordinator coordinator;

    @Override
    protected void initializing(Context context) throws InitializingException {
        super.initializing(context);

        //region 绑定协调者
        this.coordinator = coordinator != null
                ? coordinator
                : context.get(Coordinator.class);
        this.coordinator.initialize(context);
        //endregion
    }

    @Override
    protected void destroying() throws DestroyingException {
        super.destroying();

        this.coordinator.destroy();
        this.coordinator = null;
    }

    @Override
    protected void starting() throws StartingException {
        super.starting();

        try {
            // region 声明启动
            byte[] data = marshall(null);
            // 同步创建临时节点
            coordinator.create(ENGINES_ROOT + SPRT + name, data, false, false);
            coordinator.watch(ENGINES_ROOT + SPRT + name, new CloseHandler());
            //endregion
        } catch (Exception e) {
            throw new StartingException(e);
        }
    }

    @Override
    protected void shutting() throws ShuttingException {
        super.shutting();

        try {
            coordinator.delete(ENGINES_ROOT + SPRT + name, -1, false, false, new CloseHandler());
        } catch (CoordinatorException e) {
            throw new ShuttingException(e);
        }
    }

    public class CloseHandler implements NodeWatcher, Callback<Coordinator.DeleteResult, CallbackException> {

        @Override
        public void onWatched(NodeEvent event) throws Exception {

        }

        @Override
        public void call(boolean success, Coordinator.DeleteResult result, CallbackException exception) throws Exception {
            shutdown();
            destroy();
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Coordinator getCoordinator() {
        return coordinator;
    }

    public void setCoordinator(Coordinator coordinator) {
        this.coordinator = coordinator;
    }
}
